#include "LogMessage.hpp"

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

#include <strings.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


const int BUFFER_SIZE = 128;
const int EXEC_SIZE = 512;

class ServerUDP
{
public:
            /*这里将port和IP换一下位置，不然创建对象的时候会出问题*/
    ServerUDP(uint16_t port = 0, const std::string &IP = "", int sock = -1)
        : _IP(IP), _port(port), _sock(sock)
    {}

    // 服务端初始化
    void InitServer()
    {
        // 创建套接字
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sock == -1) // 创建失败就退出
        {
            LogMessage(FATAL, _F, _L, "creat socket fail ::%s", strerror(errno));
            exit(2);
        }

        sockaddr_in local;            // 初始化的时候全部清零，可以用memset，也可以用bzero直接清零
        bzero(&local, sizeof(local)); // bzero会将local中的内容清零，这样local中的zero成员就不用管了
        // sin_zero已经初始化为0
        local.sin_family = AF_INET; // sin_family
        local.sin_addr.s_addr = _IP == "" ? INADDR_ANY : inet_addr(_IP.c_str()); // sin_addr
        local.sin_port = htons(_port); // sin_port
        
                            /*用reinterpret_cast强转一下*/
        if(bind(_sock, reinterpret_cast<const sockaddr*>(&local), sizeof(local)) < 0)
        {
            LogMessage(FATAL, _F, _L, "bind fail ::%s", strerror(errno));
            exit(3);
        }

        LogMessage(NORMAL, _F, _L, "InitServer success");
    }

    // 服务端启动
    void StartServer()
    {
        char buffer[BUFFER_SIZE] = {0};
        // 服务器要写成死循环
        for(;;)
        {
            // 1.接收数据
            sockaddr_in peer; // sockaddr_in对象，倒数第二个参数
            socklen_t len = sizeof(peer); // 输入输出型参数
            bzero(&peer, len); // 注意传入前要初始化为0
            
            LogMessage(NORMAL, _F, _L, "recving...");
                                                                        /*注意强转*/
            ssize_t res = recvfrom(_sock, buffer, BUFFER_SIZE, 0, reinterpret_cast<sockaddr*>(&peer), &len);
            

            if(res > 0)
            {
                // 接收到数据了，最后一位要置为0
                buffer[res] = 0;
                // 2.分析和处理数据，这里让服务端执行客户端发来的命令
                
            }
            LogMessage(NORMAL, _F, _L, "receiv success");
            
            // 不过先将对方主机的IP和端口号找出来
            std::string cli_IP = inet_ntoa(peer.sin_addr);
            uint16_t cli_port = ntohs(peer.sin_port);
            // printf("[%s:%d]:%s\n", cli_IP.c_str(), cli_port, buffer);

                /*发送方的IP + port组成的字符串*/
            std::string sender;
            sender += '[' + cli_IP + ':' + std::to_string(cli_port) + ']';
            _clients.insert(std::pair<std::string, sockaddr_in>(sender, peer));
            
            sender += '#';
            sender += buffer;
            std::cout << "sender::" << sender << std::endl;
            // 写回数据                         /*0表示阻塞写*/
            for(auto & kv : _clients)
            {
                std::cout << kv.first << std::endl;
                sendto(_sock, sender.c_str(), sender.size(), 0, reinterpret_cast<sockaddr*>(&kv.second), len);
            }
        }
    }

    ~ServerUDP()
    {
        if(_sock >= 0)
            close(_sock);
    }

private:
    std::string _IP; // 服务端的IP
    uint16_t _port;  // 服务端的端口号
    int _sock;
    std::unordered_map<std::string, struct sockaddr_in> _clients;
};

/*********************************简易shell***********************************/
// const int BUFFER_SIZE = 128;
// const int EXEC_SIZE = 512;

// class ServerUDP
// {
// public:
//             /*这里将port和IP换一下位置，不然创建对象的时候会出问题*/
//     ServerUDP(uint16_t port = 0, const std::string &IP = "", int sock = -1)
//         : _IP(IP), _port(port), _sock(sock)
//     {}

//     // 服务端初始化
//     void InitServer()
//     {
//         // 创建套接字
//         _sock = socket(AF_INET, SOCK_DGRAM, 0);
//         if (_sock == -1) // 创建失败就退出
//         {
//             LogMessage(FATAL, _F, _L, "creat socket fail ::%s", strerror(errno));
//             exit(2);
//         }

//         sockaddr_in local;            // 初始化的时候全部清零，可以用memset，也可以用bzero直接清零
//         bzero(&local, sizeof(local)); // bzero会将local中的内容清零，这样local中的zero成员就不用管了
//         // sin_zero已经初始化为0
//         local.sin_family = AF_INET; // sin_family
//         local.sin_addr.s_addr = _IP == "" ? INADDR_ANY : inet_addr(_IP.c_str()); // sin_addr
//         local.sin_port = htons(_port); // sin_port
        
//                             /*用reinterpret_cast强转一下*/
//         if(bind(_sock, reinterpret_cast<const sockaddr*>(&local), sizeof(local)) < 0)
//         {
//             LogMessage(FATAL, _F, _L, "bind fail ::%s", strerror(errno));
//             exit(3);
//         }

//         LogMessage(NORMAL, _F, _L, "InitServer success");
//     }

//     // 服务端启动
//     void StartServer()
//     {
//         char buffer[BUFFER_SIZE] = {0};
//         // 服务器要写成死循环
//         for(;;)
//         {
//             // 1.接收数据
//             sockaddr_in peer; // sockaddr_in对象，倒数第二个参数
//             socklen_t len = sizeof(peer); // 输入输出型参数
//             bzero(&peer, len); // 注意传入前要初始化为0
//                                                                         /*注意强转*/
//             ssize_t res = recvfrom(_sock, buffer, BUFFER_SIZE, 0, reinterpret_cast<sockaddr*>(&peer), &len);

//             char execBuff[EXEC_SIZE] = {0};
//             std::string execRes;
//             if(res > 0)
//             {
//                 // 接收到数据了，最后一位要置为0
//                 buffer[res] = 0;
//                 // 2.分析和处理数据，这里让服务端执行客户端发来的命令
                
//                 // 不要rm / rmdir命令
//                 if(strcasestr(buffer, "rm") != nullptr || strcasestr(buffer, "rmdir") != nullptr)
//                 {
//                     std::string err_message = "You can't use rm / rmdir";  
//                     sendto(_sock, err_message.c_str(), err_message.size(), 0, (struct sockaddr *)&peer, len);
//                     continue;
//                 }
//                 // 执行命令
//                 FILE* pf = popen(buffer, "r");
//                 if(pf == nullptr)
//                 {
//                     printf("popen err\n");
//                     exit(4);
//                 }

//                 // 让所有的结果拼到一块
//                 while(fgets(execBuff, EXEC_SIZE, pf) != nullptr)
//                 {
//                     execRes += execBuff;
//                 }
//                 pclose(pf);
//             }
            
//             std::cout << execRes << std::endl;
//             // 不过先将对方主机的IP和端口号找出来
//             std::string cli_IP = inet_ntoa(peer.sin_addr);
//             uint16_t cli_port = ntohs(peer.sin_port);
//             // printf("[%s:%d]:%s\n", cli_IP.c_str(), cli_port, buffer);

//             // 写回数据                         /*0表示阻塞写*/
//             sendto(_sock, execRes.c_str(), execRes.size(), 0, reinterpret_cast<sockaddr*>(&peer), len);
//         }
//     }

//     ~ServerUDP()
//     {
//         if(_sock >= 0)
//             close(_sock);
//     }

// private:
//     std::string _IP; // 服务端的IP
//     uint16_t _port;  // 服务端的端口号
//     int _sock;
// };


/******************************************echo 服务器*******************************************************/
// #include "LogMessage.hpp"

// #include <iostream>
// #include <string>

// #include <strings.h>

// #include <sys/types.h>
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>

// const int BUFFER_SIZE = 128;

// class ServerUDP
// {
// public:
//             /*这里将port和IP换一下位置，不然创建对象的时候会出问题*/
//     ServerUDP(uint16_t port = 0, const std::string &IP = "", int sock = -1)
//         : _IP(IP), _port(port), _sock(sock)
//     {}

//     // 服务端初始化
//     void InitServer()
//     {
//         // 创建套接字
//         _sock = socket(AF_INET, SOCK_DGRAM, 0);
//         if (_sock == -1) // 创建失败就退出
//         {
//             LogMessage(FATAL, _F, _L, "creat socket fail ::%s", strerror(errno));
//             exit(2);
//         }

//         sockaddr_in local;            // 初始化的时候全部清零，可以用memset，也可以用bzero直接清零
//         bzero(&local, sizeof(local)); // bzero会将local中的内容清零，这样local中的zero成员就不用管了
//         // sin_zero已经初始化为0
//         local.sin_family = AF_INET; // sin_family
//         local.sin_addr.s_addr = _IP == "" ? INADDR_ANY : inet_addr(_IP.c_str()); // sin_addr
//         local.sin_port = htons(_port); // sin_port

//                             /*用reinterpret_cast强转一下*/
//         if(bind(_sock, reinterpret_cast<const sockaddr*>(&local), sizeof(local)) < 0)
//         {
//             LogMessage(FATAL, _F, _L, "bind fail ::%s", strerror(errno));
//             exit(3);
//         }

//         LogMessage(NORMAL, _F, _L, "InitServer success");
//     }

//     // 服务端启动
//     void StartServer()
//     {
//         char buffer[BUFFER_SIZE] = {0};
//         // 服务器要写成死循环
//         for(;;)
//         {
//             // 1.接收数据
//             sockaddr_in peer; // sockaddr_in对象，倒数第二个参数
//             socklen_t len = sizeof(peer); // 输入输出型参数
//             bzero(&peer, len); // 注意传入前要初始化为0
//                                                                         /*注意强转*/
//             ssize_t res = recvfrom(_sock, buffer, BUFFER_SIZE, 0, reinterpret_cast<sockaddr*>(&peer), &len);
//             if(res > 0)
//             {
//                 // 接收到数据了，最后一位要置为0
//                 buffer[res] = 0;
//             }

//             // 2.分析和处理数据，这里只进行简单打印即可
//             // 不过先将对方主机的IP和端口号找出来
//             std::string cli_IP = inet_ntoa(peer.sin_addr);
//             uint16_t cli_port = ntohs(peer.sin_port);
//             printf("[%s:%d]:%s\n", cli_IP.c_str(), cli_port, buffer);

//             // 写回数据                         /*0表示阻塞写*/
//             sendto(_sock, buffer, strlen(buffer), 0, reinterpret_cast<sockaddr*>(&peer), len);
//         }
//     }

//     ~ServerUDP()
//     {
//         if(_sock >= 0)
//             close(_sock);
//     }

// private:
//     std::string _IP; // 服务端的IP
//     uint16_t _port;  // 服务端的端口号
//     int _sock;
// };
